package com.tencent.sr.iris.activity.service.event.task;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSONObject;
import com.tencent.sr.iris.activity.common.enums.TaskEstimateStatusEnum;
import com.tencent.sr.iris.activity.common.enums.UserTaskStatusEnum;
import com.tencent.sr.iris.activity.common.util.TimeUtils;
import com.tencent.sr.iris.activity.dependency.dto.data.CommissionInfoDTO;
import com.tencent.sr.iris.activity.domain.event.dto.ActivityDTO;
import com.tencent.sr.iris.activity.domain.event.dto.ActivityTaskDTO;
import com.tencent.sr.iris.activity.domain.event.dto.SpecialOldTttResultDTO;
import com.tencent.sr.iris.activity.interfaces.event.dto.ActivityEventDTO;
import com.tencent.sr.iris.activity.repository.entity.TIrisActivityAwardRecordDO;
import com.tencent.sr.iris.activity.repository.entity.TIrisUserTaskRecordDO;
import com.tencent.sr.iris.activity.service.activity.ActivityCommonService;
import com.tencent.sr.iris.activity.service.activity.IrisUserTaskRecordService;
import com.tencent.sr.iris.activity.service.config.ActivityConfig;
import com.tencent.sr.iris.activity.service.event.util.ActivityCommonUtilService;
import com.tencent.sr.iris.activity.service.event.vo.BaseUserTaskDataVO;
import com.tencent.sr.iris.activity.service.event.vo.TaskExecutorExtendInfo;
import com.tencent.sr.iris.activity.service.util.IdCreateorUtil;
import com.tencent.sr.iris.activity.service.util.LocalDateUtil;
import com.tencent.sr.rmall.common.exception.retail.TRetailBizException;
import com.tencent.sr.rmall.common.exception.retail.TRetailErrorException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Slf4j
@Component
public class IrisCommissionTaskExecutor extends AbstractIrisTaskExecutor {

    @Resource
    private ActivityCommonService activityCommonService;

    @Resource
    private IrisUserTaskRecordService userTaskRecordService;

    @Resource
    private IdCreateorUtil idCreateorUtil;

    @Resource
    private ActivityConfig activityConfig;

    @Resource
    private ActivityCommonUtilService activityCommonUtilService;


    @Override
    public void process(ActivityEventDTO msg, ActivityDTO activity, ActivityTaskDTO task,
            List<String> eventHandingInfoList, TaskExecutorExtendInfo taskExecutorExtendInfo) {
        String uid = msg.getUid();

        //获取任务执行周期
        Long eventTimeMillis = msg.getEventTime();
        LocalDateTime eventTime = LocalDateTime
                .ofInstant(Instant.ofEpochMilli(eventTimeMillis), ZoneId.systemDefault());
        String period = eventTime.format(DateTimeFormatter.ofPattern(activity.getPeriod()));
        log.info("任务执行周期,period={}", period);

        //5月1日0点起，处理老团推团时间
        SpecialOldTttResultDTO oldTttResult = SpecialOldTttResultDTO.builder().satisfy(true)
                .oldTttEndTime(null).build();
        DateTime strictStandardStartTime = DateUtil.parse(activityConfig.getStrictStandardStartTimeByUid(uid));
        long standardStartTimeStamp = strictStandardStartTime.getTime();
        if (eventTimeMillis >= standardStartTimeStamp) {
            oldTttResult = activityCommonService.handleSpecialOldTttCache(uid, eventTimeMillis);
        }

        if (!oldTttResult.isSatisfy()) {
            log.info("老团推团未结束，无法参与月月领活动,activityId={}, msg={}", activity.getBizId(), JSONObject.toJSONString(msg));
            eventHandingInfoList.add("月月领不满足活动准入规则,errorMsg=老团推团未结束，无法参与月月领活动");
            return;
        }

        Date oldTttEndTime = oldTttResult.getOldTttEndTime();
        if (oldTttEndTime != null && (oldTttEndTime.getTime() < task.getStartTime().getTime()
                || oldTttEndTime.getTime() > task.getEndTime().getTime()
                || oldTttEndTime.getTime() > eventTimeMillis)) {
            log.info(
                    "任务处理：老团推团结束第二天时间不在任务时间范围内，不处理，eventIdempotent:{},eventTime:{},taskId:{},oldTttEndTime:{},taskTime:{}-{}",
                    msg.getIdempotent(), eventTime, task.getBizId(), oldTttEndTime, task.getStartTime(),
                    task.getEndTime());
            throw new TRetailBizException("老团推团结束第二天时间不在任务时间范围内，不处理");
        }

        //解析任务执行条件门槛值
        parseTaskCondition(task, uid);
        //查询任务完成进度
        log.info("查询用户任务进度记录,uid={},activityBizId={},taskBizId={},period={}", uid, activity.getBizId(),
                task.getBizId(), period);
        TIrisUserTaskRecordDO userTaskRecordDO = queryUserTaskRecord(uid, activity.getBizId(),
                task.getBizId(), period);
        log.info("查询用户任务进度记录,userTaskRecordDO={}", JSONObject.toJSONString(userTaskRecordDO));
        if (userTaskRecordDO == null) {
            //不处理非本月且未参与任务的事件
            if (YearMonth.from(eventTime).compareTo(YearMonth.now()) != 0) {
                throw new TRetailBizException("事件时间不在当前月份内且之前为成功参与任务，不处理");
            }
            //初始化新增用户活动任务完成进度
            userTaskRecordDO = initUserTaskRecordDO(activity, task, msg, period, eventTime, oldTttEndTime);
        } else {
            //重新计算开始时间
            Date currentTaskStartTime = userTaskRecordDO.getCurrentTaskStartTime();
            Date startTime = initCurrentTaskStartTime(uid, task, eventTime, oldTttEndTime);
            userTaskRecordDO.setCurrentTaskStartTime(startTime);
            userTaskRecordService.updateUserTaskStartTime(userTaskRecordDO);
            log.info("重新计算任务开始时间，uid：{}，activityBizId：{}，taskBizId：{}，参与记录id：{}，变更前任务开始时间：{}，变更后任务开始时间：{}",
                    uid, activity.getBizId(), task.getBizId(), userTaskRecordDO.getBizId(),
                    DateUtil.formatDateTime(currentTaskStartTime), DateUtil.formatDateTime(startTime));
        }

        if (UserTaskStatusEnum.FINISHED.getCode() == userTaskRecordDO.getUserTaskStatus()) {
            //已完成任务,直接跳过
            log.info("任务已完成,不再更新该任务进度,userTaskRecordId={}", userTaskRecordDO.getBizId());
            eventHandingInfoList.add("任务已完成,不再更新该任务进度");
            return;
        }
        if (UserTaskStatusEnum.UNFINISHED.getCode() == userTaskRecordDO.getUserTaskStatus()) {
            //未完成任务,直接跳过
            log.info("任务未完成,不再更新该任务进度,userTaskRecordId={}", userTaskRecordDO.getBizId());
            eventHandingInfoList.add("任务未完成,不再更新该任务进度");
            return;
        }

        //任务执行条件数据加载
        log.info("查询用户当前佣金及分享次数,uid={},eventTime={}", uid, eventTime);
        conditionDataPreLoad(userTaskRecordDO, uid);
        log.info("查询用户当前佣金及分享次数,uid:{},estimateCommission={},commission={},shareCount={}",
                uid, userTaskRecordDO.getEstimateCommission(), userTaskRecordDO.getCommission(),
                userTaskRecordDO.getShareCount());

        //任务进度完成状态校验
        fillTaskRecordStatus(msg, activity, task, userTaskRecordDO, LocalDate.now());

        TIrisActivityAwardRecordDO awardRecordDO = null;
        //任务完成,发放权益
        if (UserTaskStatusEnum.FINISHED.getCode() == userTaskRecordDO.getUserTaskStatus()) {
            log.info("发放用户权益");
            awardRecordDO = activityCommonService.sendAwardForSupervisor(userTaskRecordDO, task);
            log.info("发放用户权益结果,awardRecord={}", JSONObject.toJSONString(awardRecordDO));
        }
        //更新用户活动任务完成进度
        userTaskRecordService.updateUserTaskRecordStatus(userTaskRecordDO, awardRecordDO);
    }

    @Override
    public void fillTaskRecordStatus(ActivityEventDTO eventDTO, ActivityDTO act, ActivityTaskDTO task,
            TIrisUserTaskRecordDO userTaskRecordDO, LocalDate currentLocalDate) {
        LocalDate currentTaskStartDate = userTaskRecordDO.getCurrentTaskStartTime().toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
        LocalDate currentTaskEndDate = userTaskRecordDO.getCurrentTaskEndTime().toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
        int plusDays = activityConfig.getCommissionPlusDays(userTaskRecordDO.getUid());
        LocalDate currentTaskEndDatePlus60 = userTaskRecordDO.getCurrentTaskEndTime().toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate().plusDays(plusDays);
        Integer estimateCommission = userTaskRecordDO.getEstimateCommission();
        Integer commission = userTaskRecordDO.getCommission();
        Integer shareCount = userTaskRecordDO.getShareCount();

        //在任务周期内
        if (LocalDateUtil.isLocalDateBetween(currentLocalDate, currentTaskStartDate, currentTaskEndDate)) {
            //设置预估佣金任务完成状态
            if (estimateCommission >= task.getCommissionLimit()
                    && shareCount >= task.getShareTimeLimit()) {
                userTaskRecordDO.setEstimateUserTaskStatus(UserTaskStatusEnum.FINISHED.getCode());
            } else {
                userTaskRecordDO.setEstimateUserTaskStatus(UserTaskStatusEnum.PROGRESS.getCode());
            }
            //实际佣金及分享次数条件判断
            if (commission >= task.getCommissionLimit()
                    && shareCount >= task.getShareTimeLimit()) {
                //任务已完成
                userTaskRecordDO.setUserTaskStatus(UserTaskStatusEnum.FINISHED.getCode());
            } else {
                userTaskRecordDO.setUserTaskStatus(UserTaskStatusEnum.PROGRESS.getCode());
            }
            //在任务周期结束后60天内
        } else if (currentLocalDate.isAfter(currentTaskEndDate)
                && (currentLocalDate.equals(currentTaskEndDatePlus60) || currentLocalDate
                .isBefore(currentTaskEndDatePlus60))) {
            //有效分享次数没达成，直接判断为未完成
            if (shareCount < task.getShareTimeLimit()) {
                userTaskRecordDO.setEstimateUserTaskStatus(UserTaskStatusEnum.UNFINISHED.getCode());
                userTaskRecordDO.setUserTaskStatus(UserTaskStatusEnum.UNFINISHED.getCode());
                return;
            }

            LocalDate endDatePlusOne = currentTaskEndDate.plusDays(1);
            if (estimateCommission >= task.getCommissionLimit()) {
                userTaskRecordDO.setEstimateUserTaskStatus(UserTaskStatusEnum.FINISHED.getCode());
            } else if (currentLocalDate.isAfter(endDatePlusOne)) {
                //预估佣金没达成，且已过任务结束时间24小时，直接判断为未完成
                userTaskRecordDO.setEstimateUserTaskStatus(UserTaskStatusEnum.UNFINISHED.getCode());
                userTaskRecordDO.setUserTaskStatus(UserTaskStatusEnum.UNFINISHED.getCode());
                return;
            }

            //实际佣金条件判断
            if (commission >= task.getCommissionLimit()) {
                userTaskRecordDO.setUserTaskStatus(UserTaskStatusEnum.FINISHED.getCode());
            } else {
                userTaskRecordDO.setUserTaskStatus(UserTaskStatusEnum.PROGRESS.getCode());
            }
            //任务周期结束60天后
        } else if (currentLocalDate.isAfter(currentTaskEndDatePlus60)) {
            //实际佣金及分享次数条件判断
            if (commission >= task.getCommissionLimit()
                    && shareCount >= task.getShareTimeLimit()) {
                //任务已完成
                userTaskRecordDO.setUserTaskStatus(UserTaskStatusEnum.FINISHED.getCode());
                userTaskRecordDO.setEstimateUserTaskStatus(UserTaskStatusEnum.FINISHED.getCode());
            } else {
                userTaskRecordDO.setUserTaskStatus(UserTaskStatusEnum.UNFINISHED.getCode());
                userTaskRecordDO.setEstimateUserTaskStatus(UserTaskStatusEnum.UNFINISHED.getCode());
            }
        }
    }

    @Override
    public boolean executeAward(ActivityEventDTO event, ActivityDTO act, ActivityTaskDTO task) {
        return false;
    }

    @Override
    public boolean checkTaskThreshold(ActivityEventDTO event, ActivityDTO act, ActivityTaskDTO task,
            BaseUserTaskDataVO userTaskDataVO) {
        return false;
    }

    @Override
    public BaseUserTaskDataVO prepareUserTaskData(ActivityEventDTO event, ActivityDTO act, ActivityTaskDTO task) {
        return null;
    }

    private void parseTaskCondition(ActivityTaskDTO task, String uid) {
        task.parseLimitCondition();
    }


    private void conditionDataPreLoad(TIrisUserTaskRecordDO userTaskRecordDO, String uid) {
        String startTimeStr = TimeUtils.parse(userTaskRecordDO.getCurrentTaskStartTime(), TimeUtils.YYYY_MM_DD);
        String endTimeStr = TimeUtils.parse(userTaskRecordDO.getCurrentTaskEndTime(), TimeUtils.YYYY_MM_DD);
        log.info("查询用户当前佣金及分享次数,uid={},startTime={},endTime={}", uid, startTimeStr, endTimeStr);
        CommissionInfoDTO commissionInfoDTO = activityCommonService.queryCommissionInfo(uid, startTimeStr, endTimeStr);
        userTaskRecordDO.setEstimateCommission(commissionInfoDTO.getEstimateCommission());

        //任务周期结束时间 + 60天以后,计算是否达到门槛：
        //新增判断：T+60以后(不包含T+60天)，【分佣成功】+【订单交易完成且分佣未取消】是否达门槛（T为下单时间）
        int plusDays = activityConfig.getCommissionPlusDays(userTaskRecordDO.getUid());
        LocalDate taskEndDatePlus60 = userTaskRecordDO.getCurrentTaskEndTime().toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate().plusDays(plusDays);

        Integer commission = Objects.isNull(commissionInfoDTO.getCommission()) ? 0 : commissionInfoDTO.getCommission();
        LocalDate currentLocalDate = LocalDate.now();
        if (currentLocalDate.isAfter(taskEndDatePlus60)) {
            Integer waitCommissionAmt = Objects.isNull(commissionInfoDTO.getWaitCommissionAmt()) ? 0
                    : commissionInfoDTO.getWaitCommissionAmt();
            commission = commission + waitCommissionAmt;
        }
        userTaskRecordDO.setCommission(commission);

        userTaskRecordDO.setShareCount(commissionInfoDTO.getShareUvToEndOfMonth());
        userTaskRecordDO.setGmv(commissionInfoDTO.getGmv());

        String extInfo = activityCommonUtilService.buildTaskRecordExtInfo(userTaskRecordDO.getExtInfo(), commissionInfoDTO);
        userTaskRecordDO.setExtInfo(extInfo);
    }

    private TIrisUserTaskRecordDO initUserTaskRecordDO(ActivityDTO activity, ActivityTaskDTO taskDTO,
            ActivityEventDTO msg,
            String period, LocalDateTime eventTime, Date oldTttEndTime) {
        TIrisUserTaskRecordDO userTaskRecordDO = new TIrisUserTaskRecordDO();
        userTaskRecordDO.setBizId(idCreateorUtil.genId());
        userTaskRecordDO.setUid(msg.getUid());
        userTaskRecordDO.setPid(msg.getPid());
        userTaskRecordDO.setActivityId(activity.getBizId());
        userTaskRecordDO.setTaskId(taskDTO.getBizId());
        userTaskRecordDO.setActivityType(activity.getActivityType());
        userTaskRecordDO.setPeriodType(activity.getPeriodType());
        userTaskRecordDO.setTaskPeriod(period);
        userTaskRecordDO.setUserTaskStatus(UserTaskStatusEnum.PROGRESS.getCode());
        userTaskRecordDO.setEstimateUserTaskStatus(TaskEstimateStatusEnum.PROGRESS.getCode());
        userTaskRecordDO
                .setCurrentTaskStartTime(initCurrentTaskStartTime(msg.getUid(), taskDTO, eventTime, oldTttEndTime));
        userTaskRecordDO.setCurrentTaskEndTime(initCurrentTaskEndTime(eventTime, taskDTO));
        userTaskRecordDO.setTier(taskDTO.getTier());
        userTaskRecordService.saveUserTaskRecord(userTaskRecordDO);
        return userTaskRecordDO;
    }

    private Date initCurrentTaskEndTime(LocalDateTime localDateTime, ActivityTaskDTO taskDTO) {
        //获取用户参与活动当月结束时间
        LocalDateTime monthLastDay = localDateTime.with(TemporalAdjusters.lastDayOfMonth());
        LocalDateTime montLastTime = LocalDateTime
                .of(monthLastDay.getYear(), monthLastDay.getMonth(), monthLastDay.getDayOfMonth(), 23, 59, 59);
        //任务结束时间
        LocalDateTime taskEndTime = taskDTO.getEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        //任务进度结束时间为 min(参与当月月底时间,任务结束时间)
        LocalDateTime currentTaskEndTime = taskEndTime.isBefore(montLastTime) ? taskEndTime : montLastTime;
        Date endDate = Date.from(currentTaskEndTime.atZone(ZoneId.systemDefault()).toInstant());
        return endDate;
    }

    private Date initCurrentTaskStartTime(String uid, ActivityTaskDTO taskDTO,
            LocalDateTime eventTime, Date oldTttEndTime) {
        Long oldTttEndTimeMills = Optional.ofNullable(oldTttEndTime).map(Date::getTime).orElse(Long.MIN_VALUE);
        //任务开始时间，此处任务开始时间在活动校验时，已处理特邀老ttt结束时间
        Date taskStartTime = taskDTO.getStartTime();
        //获取当月起始时间
        LocalDateTime monthFirstDay = eventTime.with(TemporalAdjusters.firstDayOfMonth());
        //查询用户成为见习会员时间
        Long traineeTime = activityCommonService.queryTraineeTime(uid);
        if (traineeTime == null) {
            log.error("查询成为见习时间为空，初始化任务开始时间失败，uid：{}，activityId：{}，taskId：{}", uid, taskDTO.getActivityId(),
                    taskDTO.getBizId());
            throw new TRetailErrorException("查询成为见习时间为空，初始化任务开始时间失败");
        }

        //查询佣金 max（成为见习会员的时间,佣金变化时间当月1号) <= 佣金变化时间 <= 佣金变化时间当月最后一天
        long timestamp = NumberUtil
                .max(monthFirstDay.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(), oldTttEndTimeMills,
                        traineeTime);
        LocalDateTime startTime = Instant.ofEpochMilli(timestamp).atZone(ZoneOffset.systemDefault()).toLocalDateTime();
        /*记录开始时间,只精确到当天*/
        return new Date(
                startTime.withHour(0).withMinute(0).withSecond(0).atZone(ZoneId.systemDefault()).toInstant()
                        .toEpochMilli());
    }

}
